import { defineGlobalProperty, isMyRoom, LifeCycles } from '@/ayaka'
import { FlagPrefix } from './types'

/**
 * 旗帜控制器，用于简化旗帜的操作。
 *
 * 我们规定旗帜的命名规规范为：前缀_房间_id，房间表示所属的房间，不存在时为 global。_id 为可选项。
 * @example
 * - source_W1N1
 * - source_W1N1_1
 * - source_global
 */
export default class FlagController {
    /**
     * 不同前缀的旗帜映射
     */
    public static prefixFlagMap = new Map<FlagPrefix, Flag[]>()

    /**
     * 更新旗帜
     */
    public static update() {
        FlagController.prefixFlagMap.clear()

        for (const flagName in Game.flags) {
            const flag = Game.flags[flagName]
            const [prefix, room, id] = flagName.split('_')
            const flagPrefx = prefix as FlagPrefix

            if (flag.memory.setPosition) {
                const [x, y, roomName] = flag.memory.setPosition.split('/')
                flag.setPosition(new RoomPosition(+x, +y, roomName))
                delete flag.memory.setPosition
                flag._setPositioned = true
            }

            flag._creeps = []
            flag._belongRoom = Game.rooms[room]
            flag._room = Game.rooms[flag.pos.roomName]

            if (!flag.memory.prefix) {
                flag.memory.prefix = flagPrefx
            }

            if (!flag.memory.belong) {
                flag.memory.belong = room || 'global'
            }

            if (!flag.memory.id) {
                flag.memory.id = id || ''
            }

            if (!FlagController.prefixFlagMap.has(flagPrefx)) {
                FlagController.prefixFlagMap.set(flagPrefx, [])
            }
            FlagController.prefixFlagMap.get(flagPrefx)?.push(flag)
        }
    }

    /**
     * 获取指定前缀的旗帜
     */
    public static getFlagsByPrefix(prefix: FlagPrefix) {
        return FlagController.prefixFlagMap.get(prefix) || []
    }

    /**
     * 获取指定前缀和房间的旗帜
     */
    public static getFlagByPrefixAndRoom(prefix: FlagPrefix, room: string): Flag | undefined {
        return Game.flags[`${prefix}_${room}`]
    }

    /**
     * 获取指定前缀和房间的旗帜
     */
    public static getFlagsByPrefixAndRoom(prefix: FlagPrefix, room: string) {
        return FlagController.getFlagsByPrefix(prefix).filter((flag) => flag.memory.belong === room)
    }

    /**
     * 创建指定前缀，房间和 id 的旗帜
     */
    public static createFlag(
        pos: RoomPosition,
        prefix: FlagPrefix,
        belong: string,
        id: string,
        color: ColorConstant,
        secondaryColor: ColorConstant,
        memory: Partial<FlagMemory> = {},
    ) {
        const flagName = `${prefix}_${belong}_${id}`
        const name = pos.createFlag(flagName, color, secondaryColor)
        if (typeof name === 'string') {
            Memory.flags[name] = { ...(Memory.flags[name] || {}), ...memory }
        }
        return name
    }

    /**
     * 重新创建旗帜，生成 id
     *
     * @returns 创建成功返回新旗帜名，失败返回 undefined
     */
    public static reCreateFlag(flag: Flag, extraMemory: Partial<FlagMemory> = {}) {
        const { pos, color, secondaryColor } = flag
        const { prefix, belong, id } = flag.memory
        if (!prefix || !belong) {
            return
        }

        const room = Object.values(Game.rooms)[0]
        if (!room) return

        const time = Game.time.toString()
        const name = room.createFlag(25, 25, `${prefix}_${belong}_${id}_${time}`, color, secondaryColor)
        // 返回字符串表示创建成功
        if (typeof name === 'string') {
            // 移除必定成功
            flag.remove()
            delete Memory.flags[flag.name]
            Memory.flags[name] = { ...flag.memory, ...extraMemory, setPosition: `${pos.x}/${pos.y}/${pos.roomName}` }
            return name
        }

        return
    }

    /**
     * 返回一个可以创建旗帜的位置
     */
    public static getCreateFlagPos(room?: Room) {
        // 找自己的房间随便返回一个坐标
        if (!room) {
            room = Object.values(Game.rooms).find((room) => isMyRoom(room))
        }
        if (!room) return

        // 随机位置，不包含边界
        const x = Math.floor(Math.random() * 49) + 1
        const y = Math.floor(Math.random() * 49) + 1
        return new RoomPosition(x, y, room.name)
    }
}

/**
 * 更新旗帜
 */
export const updateFlag: LifeCycles = {
    tickStart() {
        FlagController.update()
    },
}

defineGlobalProperty('FlagController', {
    value: FlagController,
})
